from __future__ import annotations

from datetime import datetime
from typing import Optional, List, Dict, Any

from sqlalchemy.dialects.mysql import insert
from loguru import logger

from core.database import DatabaseManager, db_manager
from dao.models import FuturesAndOptionsTrade


class FuturesAndOptionsTradeDao:
    def __init__(self, db_manager_in: DatabaseManager | None = None):
        self.db_manager = db_manager_in or db_manager

    def add_or_update_trade(self, trade_data: Dict[str, Any]) -> Optional[int]:
        """
        Adds a new trade or updates an existing one based on the unique constraint.
        """
        session = self.db_manager.get_session()
        try:
            stmt = insert(FuturesAndOptionsTrade).values(**trade_data)
            update_dict = {k: v for k, v in trade_data.items() if k not in ['day', 'symbol_type', 'symbol', 'trade_time']}
            stmt = stmt.on_duplicate_key_update(**update_dict)
            
            result = session.execute(stmt)
            session.commit()
            return result.lastrowid
        except Exception as e:
            logger.exception(f"Error adding or updating trade: {e}")
            session.rollback()
            return None
        finally:
            session.close()

    def get_trade(self, trade_id: int) -> Optional[Dict[str, Any]]:
        """
        Retrieves a single trade by its ID.
        """
        session = self.db_manager.get_session()
        try:
            trade = session.get(FuturesAndOptionsTrade, trade_id)
            if not trade:
                return None
            return self._to_dict(trade)
        finally:
            session.close()

    def get_trades_by_day(self, day: str) -> List[Dict[str, Any]]:
        """
        Retrieves all trades for a specific day.
        """
        session = self.db_manager.get_session()
        try:
            trades = (
                session.query(FuturesAndOptionsTrade)
                .filter(FuturesAndOptionsTrade.day == day)
                .order_by(FuturesAndOptionsTrade.trade_time)
                .all()
            )
            return [self._to_dict(t) for t in trades]
        finally:
            session.close()

    def delete_trade(self, trade_id: int) -> bool:
        """
        Deletes a trade by its ID.
        """
        session = self.db_manager.get_session()
        try:
            trade = session.get(FuturesAndOptionsTrade, trade_id)
            if not trade:
                return False
            session.delete(trade)
            session.commit()
            return True
        except Exception as e:
            logger.exception(f"Error deleting trade: {e}")
            session.rollback()
            return False
        finally:
            session.close()

    @staticmethod
    def _to_dict(trade: FuturesAndOptionsTrade) -> Dict[str, Any]:
        return {
            "id": trade.id,
            "day": trade.day,
            "symbol_type": trade.symbol_type,
            "symbol": trade.symbol,
            "amount": trade.amount,
            "cost": trade.cost,
            "trade_time": trade.trade_time.isoformat() if trade.trade_time else None,
            "create_time": trade.create_time.isoformat() if trade.create_time else None,
            "update_time": trade.update_time.isoformat() if trade.update_time else None,
        }